/**
 * 
 */
package sudoku.controller;

import java.awt.Color;
import java.awt.Cursor;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;

import sudoku.model.ChoiceModel;
import sudoku.model.SudokuModel;
import sudoku.ui.AboutUI;
import sudoku.ui.ChoiceUI;
import sudoku.ui.ComputerHelpUI;
import sudoku.ui.FontSizeUI;
import sudoku.ui.GameChoiceUI;
import sudoku.ui.GenerationBarUI;
import sudoku.ui.HelpUI;
import sudoku.ui.HistoryUI;
import sudoku.ui.ModifyUserUI;
import sudoku.ui.SudokuUI;
import sudoku.ui.Symmetry;
import sudoku.ui.UsersUI;
import sudoku.ui.WinUI;
import sudoku.util.Config;
import sudoku.util.Data;
import sudoku.util.Language;
import sudoku.util.game.Database;
import sudoku.util.game.PrintPreview;
import sudoku.util.game.SolveDLX;

/**
 * @author Romet
 * 
 */
public class Controller {

  private volatile SudokuModel model;
  private volatile SudokuUI m2ng;
  private volatile Data data;
  private volatile Config config;
  private volatile ChoiceModel choiceModel;
  private volatile ChoiceUI choiceUI;
  private volatile UsersUI usersUI;
  private volatile Language language;
  private volatile HelpUI helpUI;

  private String eelmineTekst;
  private Color eelmineV2rv;

  /**
   * Fontide suuruse muutmise aken.
   */
  public static final String FONTSIZE_EVENT = "fontSize";

  /**
   * Sümmeetrilisuse muutmine.
   */
  public static final String SYMMETRY_EVENT = "symmetry";

  /**
   * lisa andmebaasi.
   */
  public static final String LISA_EVENT = "lisa";

  /**
   * undo.
   */
  public static final String UNDO_EVENT = "undo";

  /**
   * redo.
   */
  public static final String REDO_EVENT = "redo";

  /**
   * Eesti keel.
   */
  public static final String KEEL_EESTI_EVENT = "keelEesti";

  /**
   * Inglise keel.
   */
  public static final String KEEL_INGLISE_EVENT = "keelInglise";

  /**
   * Ruudustik 9x9.
   */
  public static final String RUUDUSTIK9_EVENT = "ruudustik9";

  /**
   * Ruudustik 16x16.
   */
  public static final String RUUDUSTIK16_EVENT = "ruudustik16";

  /**
   * Printimise eelvaade.
   */
  public static final String PRINT_PREVIEW_EVENT = "printPreview";

  /**
   * Uue mängu tegemine.
   */
  public static final String UUS_M2NG_EVENT = "uusM2ng";

  /**
   * Mängu alustamine.
   */
  public static final String ALUSTA_M2NG_EVENT = "alustaM2ng";

  /**
   * Abimenüü näitemine.
   */
  public static final String ABI_MENU_EVENT = "abiMenu";

  /**
   * About menüü näitamine.
   */
  public static final String ABOUT_MENU_EVENT = "aboutMenu";

  /**
   * Mängu uuendamine internetist.
   */
  public static final String UUENDA_EVENT = "uuenda";

  /**
   * Uue sisseehitatud mängu valimine.
   */
  public static final String VALI_M2NG_EVENT = "valiM2ng";

  /**
   * Arvuti abi seaded.
   */
  public static final String COMPUTERHELP_EVENT = "computerhelp";

  /**
   * Ajaloo akna näitamine.
   */
  public static final String AJALUGU_EVENT = "ajalugu";

  /**
   * Numbrivaliku akna avamine.
   */
  public static final String VALIK_AKEN_EVENT = "valikAken";

  /**
   * Numbrivaliku akna sulgemine.
   */
  public static final String VALIK_AKEN_CLOSE_EVENT = "valikAkenClose";

  /**
   * Valitud numbri kirjutamine.
   */
  public static final String KIRJUTA_NUMBER_EVENT = "kirjutaNumber";

  /**
   * Valitud mängu paika panemine.
   */
  public static final String VALITUD_M2NG_EVENT = "valitudM2ng";

  /**
   * Mängu algseisu taastamine.
   */
  public static final String UUESTI_EVENT = "uuesti";

  /**
   * Pausi peale panemine ja maha võtmine.
   */
  public static final String PAUS_EVENT = "paus";

  /**
   * Võidu kontroll.
   */
  public static final String V6IDU_KONTROLL_EVENT = "v6it";

  /**
   * Mängu salvestamine.
   */
  public static final String SALVESTA_M2NG_EVENT = "salvestaM2ng";

  /**
   * Salvestatud mängu avamine.
   */
  public static final String AVA_M2NG_EVENT = "avaM2ng";

  /**
   * Arvuti lahendab ühe sammu.
   */
  public static final String LAHENDA_SAMM_EVENT = "lahendaSamm";

  /**
   * Arvuti lahendab mängu.
   */
  public static final String LAHENDA_M2NG_EVENT = "lahendaM2ng";

  /**
   * Kasutaja valimise aken.
   */
  public static final String VALI_KASUTAJA_EVENT = "valiKasutaja";

  /**
   * Kasutaja muutmise aken.
   */
  public static final String MUUDA_KASUTAJA_EVENT = "muudaKasutaja";

  /**
   * Valitud kasutaja seadistamine.
   */
  public static final String VALITUD_KASUTAJA_EVENT = "valitudKasutaja";

  /**
   * Mängu genereerimine
   */
  public static final String GENEREERI_M2NG_EVENT = "genereeriM2ng";

  /**
   * Kontrolleri esialgne paikapanemine.
   * 
   * @param config
   *          konfiguratsiooni klassi isend
   * @param data
   *          andmete klassi isend
   * @param model
   *          põhiakna loogika klassi isend
   * @param choiceModel
   *          valikuakna loogika klassi isend
   */
  public Controller(Language language, Config config, Data data, SudokuModel model, ChoiceModel choiceModel) {
    this.language = language;
    this.config = config;
    this.data = data;
    this.model = model;
    this.choiceModel = choiceModel;
  }

  /**
   * Sündmustega tegelemine. See meetod tegeleb kõikide sündmustega, mis
   * saadetakse kontrollerisse ning vastavalt südmusele annab tegevused
   * vajalikele meetoditele edasi.
   * 
   * @param event
   *          sündmuse nimi
   */
  public void handleEvent(final String event) {
    if (UUS_M2NG_EVENT.equals(event)) {
      model.uusModel();
      m2ng.uusM2ng();
      m2ng.seadistaLahendajad();
      m2ng.seadistaUndoRedo();
      m2ng.status("");
    } else if (FONTSIZE_EVENT.equals(event)) {
      new FontSizeUI(m2ng, config, language);
    } else if (SYMMETRY_EVENT.equals(event)) {
      new Symmetry(m2ng, config, language);
    } else if (LISA_EVENT.equals(event)) {
      JDialog d = new JDialog(m2ng);
      d.add(new JLabel(language.getUpdater_wait()));
      d.setUndecorated(true);
      d.pack();
      d.setLocation(m2ng.getLocation().x + m2ng.getWidth() / 2 - d.getWidth() / 2,
          m2ng.getLocation().y + m2ng.getHeight() / 2 - d.getHeight() / 2);
      d.setVisible(true);
      m2ng.setEnabled(false);
      Database database = new Database("add", d);
      database.setM2ng(m2ng);
      database.setModel(model);
      database.setConfig(config);
      database.setData(data);
      database.setLanguage(language);
      new Thread(database).start();
    } else if (UNDO_EVENT.equals(event)) {
      model.undo();
    } else if (REDO_EVENT.equals(event)) {
      model.redo();
    } else if (KEEL_EESTI_EVENT.equals(event)) {
      String l = model.getLevel();
      int level = 0;
      if (l.equals(language.getSudoku_diffeasy())) {
        level = 1;
      } else if (l.equals(language.getSudoku_diffmedium())) {
        level = 2;
      } else if (l.equals(language.getSudoku_diffhard())) {
        level = 3;
      } else if (l.equals(language.getSudoku_diffexpert())) {
        level = 4;
      } else if (l.equals(language.getSudoku_diffextreme())) {
        level = 5;
      }
      config.setLanguage("est");
      if (level == 1) {
        model.setLevel(language.getSudoku_diffeasy());
      } else if (level == 2) {
        model.setLevel(language.getSudoku_diffmedium());
      } else if (level == 3) {
        model.setLevel(language.getSudoku_diffhard());
      } else if (level == 4) {
        model.setLevel(language.getSudoku_diffexpert());
      } else if (level == 5) {
        model.setLevel(language.getSudoku_diffextreme());
      }
      m2ng.sudokuUI();
    } else if (KEEL_INGLISE_EVENT.equals(event)) {
      String l = model.getLevel();
      int level = 0;
      if (l.equals(language.getSudoku_diffeasy())) {
        level = 1;
      } else if (l.equals(language.getSudoku_diffmedium())) {
        level = 2;
      } else if (l.equals(language.getSudoku_diffhard())) {
        level = 3;
      } else if (l.equals(language.getSudoku_diffexpert())) {
        level = 4;
      } else if (l.equals(language.getSudoku_diffextreme())) {
        level = 5;
      }
      config.setLanguage("eng");
      if (level == 1) {
        model.setLevel(language.getSudoku_diffeasy());
      } else if (level == 2) {
        model.setLevel(language.getSudoku_diffmedium());
      } else if (level == 3) {
        model.setLevel(language.getSudoku_diffhard());
      } else if (level == 4) {
        model.setLevel(language.getSudoku_diffexpert());
      } else if (level == 5) {
        model.setLevel(language.getSudoku_diffextreme());
      }
      m2ng.sudokuUI();
    } else if (GENEREERI_M2NG_EVENT.equals(event)) {
      if (model.isGenerationNeeded()) {
        new GenerationBarUI(language, m2ng, model).drawWindow();
      } else {
        String s = model.getLevel();
        handleEvent(UUS_M2NG_EVENT);
        model.setLevel(s);
        if (s.equals(language.getSudoku_diffeasy())) {
          model.setLahendus(config.getEasy().remove(0));
          model.setNimi(language.getSudoku_diffeasy());
        } else if (s.equals(language.getSudoku_diffmedium())) {
          model.setLahendus(config.getMedium().remove(0));
        } else if (s.equals(language.getSudoku_diffhard())) {
          model.setLahendus(config.getHard().remove(0));
        } else if (s.equals(language.getSudoku_diffexpert())) {
          model.setLahendus(config.getExpert().remove(0));
        } else if (s.equals(language.getSudoku_diffextreme())) {
          model.setLahendus(config.getExtreme().remove(0));
        }
        config.salvesta();
        handleEvent(ALUSTA_M2NG_EVENT);
        m2ng.uuendaUI();
        m2ng.requestFocus();
      }
    } else if (RUUDUSTIK9_EVENT.equals(event)) {
      config.setRuudustik(9);
      config.setKast(3);
      model.uusModel();
      m2ng.uusM2ng();
      m2ng.seadistaLahendajad();
      m2ng.pack();
      m2ng.resizeM2ng();
      m2ng.seadistaUndoRedo();
    } else if (RUUDUSTIK16_EVENT.equals(event)) {
      config.setRuudustik(16);
      config.setKast(4);
      model.uusModel();
      m2ng.uusM2ng();
      m2ng.seadistaLahendajad();
      m2ng.pack();
      m2ng.resizeM2ng();
      m2ng.seadistaUndoRedo();
    } else if (PRINT_PREVIEW_EVENT.equals(event)) {
      new PrintPreview(language, model, config, m2ng);
    } else if (ALUSTA_M2NG_EVENT.equals(event)) {
      m2ng.seadistaLahendajad();
      SolveDLX sdlx = new SolveDLX(config.getRuudustik());
      sdlx.BuildSudokuMatrix();
      sdlx.SetStartingGrid(model.getLahendus(false));
      sdlx.SolveSudoku(SolveDLX.FIND_UP_TO_100);
      if (sdlx.unique) {
        if (model.getLevel().equals("")) {
          new Thread(model).start();
        }
        m2ng.alustaM2ng();
        m2ng.seadistaLahendajad();
        m2ng.seadistaUndoRedo();
        m2ng.status(language.getStatus_alusta(), Color.WHITE);
      } else {
        JOptionPane pane = new JOptionPane(language.getDLX_starterror(sdlx.getSolutionsFound()));
        pane.setOptions(new Object[] { language.getButton_yes(), language.getButton_no() });
        JDialog dialog = pane.createDialog(m2ng, language.getMessage());
        dialog.setVisible(true);
        Object selectedValue = pane.getValue();
        if (selectedValue != null && selectedValue.equals(language.getButton_yes())) {
          if (model.getLevel().equals("")) {
            new Thread(model).start();
          }
          m2ng.alustaM2ng();
          m2ng.seadistaLahendajad();
          m2ng.seadistaUndoRedo();
          m2ng.status(language.getStatus_alusta(), Color.WHITE);
        } else {
        }
      }
    } else if (ABI_MENU_EVENT.equals(event)) {
      if (helpUI == null) {
        helpUI = new HelpUI(language);
      }
      helpUI.drawWindow();
    } else if (ABOUT_MENU_EVENT.equals(event)) {
      new AboutUI(language, m2ng);
    } else if (UUENDA_EVENT.equals(event)) {
      m2ng.update(true);
    } else if (VALI_M2NG_EVENT.equals(event)) {
      GameChoiceUI gameChoiceUI = new GameChoiceUI(language, data, m2ng, this, model);
      gameChoiceUI.setGames(data.getGames());
      data.seaAndmebaas(gameChoiceUI);
    } else if (COMPUTERHELP_EVENT.equals(event)) {
      new ComputerHelpUI(m2ng, config, language);
      m2ng.seadistaLahendajad();
    } else if (AJALUGU_EVENT.equals(event)) {
      HistoryUI historyUI = new HistoryUI(language, data, m2ng);
      historyUI.ajalugu();
    } else if (VALIK_AKEN_EVENT.equals(event)) {
      if (choiceUI != null) {
        m2ng.uuendaUI();
        choiceUI.getDialog().dispose();
      }
      if (!model.isOnAlustatud()
          || !model.getSudokuButtons()[model.getValik_i()][model.getValik_j()].getV2rv().equals(config.getEsialgne())) {
        choiceModel.uusModel();
        choiceUI = new ChoiceUI(language, config, m2ng);
        choiceUI.setChoiceModel(choiceModel);
        choiceUI.setController(this);
        choiceUI.setModel(model);
        choiceUI.valik();
      }
    } else if (VALIK_AKEN_CLOSE_EVENT.equals(event)) {
      if (choiceUI != null && choiceUI.getDialog().isVisible()) {
        m2ng.uuendaUI();
        choiceUI.getDialog().dispose();
      }
    } else if (KIRJUTA_NUMBER_EVENT.equals(event)) {
      boolean abi = model.isAbi();
      model.kirjutaNumber();
      m2ng.kirjutaNumber();
      model.setAbi(abi);
      m2ng.uuendaUI();
      model.setAbi(false);
      if (!abi) {
        m2ng.uuendaBackground();
        if (config.isComputerstatus() && !model.veaKontroll()) {
          m2ng.status(language.getStatus_vigane(), Color.RED);
        } else {
          int tyhi = 0;
          int t2is = 0;
          for (int i = 0; i < model.getSudokuButtons().length; i++) {
            for (int j = 0; j < model.getSudokuButtons()[i].length; j++) {
              if (model.getSudokuButtons()[i][j].getNumber().equals(" ")) {
                tyhi++;
              } else {
                t2is++;
              }
            }
          }
          if (model.isOnAlustatud()) {
            m2ng.status(language.getStatus_veel(true, tyhi, t2is));
          } else {
            m2ng.status(language.getStatus_veel(false, tyhi, t2is), Color.CYAN);
          }
        }
      }
      handleEvent(V6IDU_KONTROLL_EVENT);
      m2ng.seadistaUndoRedo();
    } else if (VALITUD_M2NG_EVENT.equals(event)) {
      model.valitudM2ng();
      m2ng.valitudM2ng();
      handleEvent(ALUSTA_M2NG_EVENT);
    } else if (UUESTI_EVENT.equals(event)) {
      model.uuesti();
      m2ng.uuesti();
      m2ng.uuendaBackgroundAll();
      m2ng.seadistaLahendajad();
      m2ng.seadistaUndoRedo();
      m2ng.status(language.getStatus_uuesti(), Color.WHITE);
    } else if (PAUS_EVENT.equals(event)) {
      if (model.isOnPaus()) {
        m2ng.status(eelmineTekst, eelmineV2rv);
        model.setOnPaus(false);
      } else {
        eelmineTekst = m2ng.getStatusTekst();
        eelmineV2rv = m2ng.getStatusColor();
        m2ng.status(language.getSudoku_paus_label(), Color.WHITE);
        model.setOnPaus(true);
      }
      m2ng.paus();
      m2ng.seadistaLahendajad();
      m2ng.seadistaUndoRedo();
    } else if (V6IDU_KONTROLL_EVENT.equals(event)) {
      if (model.v6iduKontroll()) {
        if (choiceUI != null) {
          choiceUI.getDialog().dispose();
        }
        m2ng.v6it();
        model.v6it();
        m2ng.seadistaUndoRedo();
        new WinUI(language, m2ng, this);
      }
    } else if (SALVESTA_M2NG_EVENT.equals(event)) {
      data.salvestaM2ng();
    } else if (AVA_M2NG_EVENT.equals(event)) {
      data.avaM2ng();
    } else if (LAHENDA_SAMM_EVENT.equals(event)) {
      m2ng.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
      model.lahendaHint();
      m2ng.setCursor(Cursor.getDefaultCursor());
    } else if (LAHENDA_M2NG_EVENT.equals(event)) {
      m2ng.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
      model.lahendaM2ng();
      m2ng.setCursor(Cursor.getDefaultCursor());
    } else if (VALI_KASUTAJA_EVENT.equals(event)) {
      usersUI = new UsersUI(language, m2ng, this, config);
      usersUI.valiKasutaja();
    } else if (MUUDA_KASUTAJA_EVENT.equals(event)) {
      ModifyUserUI modifyUserUI = new ModifyUserUI(language, m2ng, this, config);
      modifyUserUI.drawWindow();
    } else if (VALITUD_KASUTAJA_EVENT.equals(event)) {
      model.uuendaModel(config.templahendus, config.tempesialgne);
      m2ng.uuendaUI();
    }
  }

  /**
   * Getter
   * 
   * @return choiceUI
   */
  public ChoiceUI getChoiceUI() {
    return choiceUI;
  }

  /**
   * Setter
   * 
   * @param helpUI
   */
  public void setHelpUI(HelpUI helpUI) {
    this.helpUI = helpUI;
  }

  /**
   * Määrab kontrolleris ära põhiakna graafika isendi.
   * 
   * @param m2ng
   *          mängu põhiakna graafika
   */
  public void setM2ng(SudokuUI m2ng) {
    this.m2ng = m2ng;
  }
}
